package savet.entidades.atributos;

import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import savet.entidades.Trabalhador;
import savet.util.DataUtil;

@Entity
@Table
public class Ferias implements Serializable {

    public static final long serialVersionUID = 8L;
    @Transient
    private Trabalhador trabalhador;
    @Id
    private Long id;
    @OneToMany
    private List<Periodo> listaFerias = new LinkedList<Periodo>();
    @OneToMany
    private List<Periodo> listaSaidas = new LinkedList<Periodo>();
    @OneToMany
    private List<AtributoData> atributosData = new LinkedList<AtributoData>();

    public List<Periodo> getListaFerias() {
        return listaFerias;
    }

    public List<AtributoData> getAtributosData() {
        return atributosData;
    }

    public void setAtributosData(List<AtributoData> atributoDatas) {

//        System.out.println("Trabalhador:" + trabalhador.getAdmissao());
        if (trabalhador.getAdmissao() != null) {
            GregorianCalendar calendar = new GregorianCalendar();
            calendar.setTime(trabalhador.getAdmissao());
            calendar.add(Calendar.YEAR, 1);
            calendar.add(Calendar.DAY_OF_YEAR, 1);
//            System.out.println("Trabalhador fim do periodo aquisitivo:" + calendar.getTime());
            for (AtributoData atributoData : atributoDatas) {
                if (atributoData.getData().before(calendar.getTime())) {
                    atributoData.setEstado(Atributo.NAO_OBRIGATORIO);
                } else {
                    atributoData.setEstado(Atributo.NAO_NOTIFICADO);
                }
            }
        }
        if (trabalhador.getAfastamento() != null) {

            for (AtributoData atributoData : atributoDatas) {
                if (atributoData.getData().after(trabalhador.getAfastamento())) {
                    atributoData.setEstado(Atributo.NAO_OBRIGATORIO);
                } else {
                    atributoData.setEstado(Atributo.NAO_NOTIFICADO);
                }
            }
        }
        this.atributosData = atributoDatas;
    }

    public void setListaFerias(List<Periodo> listaFerias) {
        this.listaFerias = listaFerias;
    }

    public List<Periodo> getListaSaidas() {
        return listaSaidas;
    }

    public void setListaSaidas(List<Periodo> listaSaidas) {
        this.listaSaidas = listaSaidas;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Trabalhador getTrabalhador() {
        return trabalhador;
    }

    public void setTrabalhador(Trabalhador trabalhador) {
        this.trabalhador = trabalhador;
    }

    /**
     * Atualiza o estado dos atributos de ferias com os periodos de gozo.
     */
    public void atualizarFerias() {
        for (AtributoData att : atributosData) {
            
            // marca atributos de ferias
            for (Periodo p : listaFerias) {
                if (contemDataEmPeriodo(p, att.getData())) {
                    att.setText("f");
                    break;
                } else if (att.getText().equals("f")) {
                    att.setText("");
                }
            }

        }

    }

    /**
     * Atualiza o estado dos atributos de ferias com os periodos de afastamento e periodos
     * concessivos.
     */
    public void atualizarSaidas() {
        for (AtributoData att : atributosData) {

            // Adiciona um periodo temporario com a data de admissao
            // Isso e utilizado para calcular os periodos concessivos
            // Apos o calculo, esse periodo e removido da lista
            final Periodo periodoTemp = new Periodo(trabalhador.getAdmissao(), trabalhador.getAdmissao());
            listaSaidas.add(periodoTemp);

            // marca atributos de afastamentos e calcula os periodos concessivos
            for (Periodo p : listaSaidas) {
                final Date dataAtributo = att.getData();
                final long diferencaDatas = getDiferencaDatas(p.getDataFim(), dataAtributo);

                if (contemDataEmPeriodo(p, dataAtributo)) {
                    att.setText("a");
                    att.setEstado(AtributoData.NAO_OBRIGATORIO);
                    break;
                } else if (att.getText().equals("a")) {
                    att.setText("");
                }

                if (diferencaDatas >= 0 && diferencaDatas <= 365) {
                    att.setEstado(AtributoData.NAO_OBRIGATORIO);
                    break;
                } else if (diferencaDatas > 365) {
                    att.setEstado(AtributoData.NAO_NOTIFICADO);
                    break;
                }
            }

            listaSaidas.remove(periodoTemp);
        }
    }

    /**
     * Verifica a existencia de uma determinada data no periodo passado como parametro.
     * <br/>
     * @param p periodo para verificacao
     * @param data data que se deseja verificar
     * @return true caso a data esteja entre o determinado periodo.
     */
    private boolean contemDataEmPeriodo(Periodo p, Date data) {
        Date dataInicio = p.getDataInicio();
        Date dataFim = p.getDataFim();

        boolean equalsDateInicio = DataUtil.equals(dataInicio, data, DataUtil.FORMATO_MES_ANO);
        boolean equalsDateFim = DataUtil.equals(dataFim, data, DataUtil.FORMATO_MES_ANO);
        boolean dateIsBetween = DataUtil.isBetween(dataInicio, dataFim, data);

        return equalsDateInicio || equalsDateFim || dateIsBetween;
    }

    /**
     *
     * @param dataFim
     * @param dataAtributo
     * @return diferenca em dias de duas datas
     */
    private long getDiferencaDatas(Date dataFim, Date dataAtributo) {
        return DataUtil.getDiferencaDatas(dataAtributo, dataFim);
    }

}
